import { WebXRCamera } from "@babylonjs/core/XR/webXRCamera";
import { WebXRDefaultExperience } from "@babylonjs/core/XR/webXRDefaultExperience";
import { WebXRInput } from "@babylonjs/core/XR/webXRInput";
import { Scene } from "@babylonjs/core/scene";
import { CreateHandleTo, IHandle, RemoveHandle } from '../../data/data-handle';
import { WebXRInputSource } from "@babylonjs/core/XR/webXRInputSource";
import { WebXRAbstractMotionController } from "@babylonjs/core/XR/motionController/webXRAbstractMotionController";
import { AbstractMesh } from "@babylonjs/core/Meshes/abstractMesh";
import { EventState } from "@babylonjs/core/Misc/observable";


/**
 * xr输入参数对象
 */
interface IXRInputOptions {
}


/**
 * xr输入
 */
class XRInput {

    private _inputSourceAddedHandles: Array<IHandle<WebXRInputSource>> = [];
    private _inputSourceRemovedHandles: Array<IHandle<WebXRInputSource>> = [];
    private _motionControllerInitHandles: Array<IHandle<WebXRAbstractMotionController>> = [];
    private _meshLoadedHandles: Array<IHandle<AbstractMesh>> = [];

    /**
     * 原生xr输入
     */
    public readonly input: WebXRInput;

    /**
     * xr相机
     */
    public readonly camera: WebXRCamera;


    constructor(xr: WebXRDefaultExperience, scene: Scene, options: IXRInputOptions) {
        this.input = xr.input;
        this.camera = xr.input.xrCamera;

        this.input.onControllerAddedObservable.add((inputSource: WebXRInputSource, state: EventState) => {
            this._inputSourceAddedHandles.forEach(handle => handle.callback(inputSource));
            inputSource.onMotionControllerInitObservable.add((motionController: WebXRAbstractMotionController, state: EventState) => {
                this._motionControllerInitHandles.forEach(handle => handle.callback(motionController));
            });
            inputSource.onMeshLoadedObservable.add((model: AbstractMesh, state: EventState) => {
                this._meshLoadedHandles.forEach(handle => handle.callback(model));
            });
        });
        this.input.onControllerRemovedObservable.add((inputSource: WebXRInputSource, state: EventState) => {
            this._inputSourceRemovedHandles.forEach(handle => handle.callback(inputSource));
        });

    }

    /**
     * 添加新增输入源时的回调函数对象
     * @param func 回调函数
     * @returns 回调函数对象
     */
    public onAdded(func: { (data: WebXRInputSource): void }): IHandle<WebXRInputSource> {
        return CreateHandleTo<WebXRInputSource>(func, this._inputSourceAddedHandles);
    }

    /**
     * 移除新增输入源时的回调函数对象
     * @param handle 回调函数对象或其id
     */
    public removeAddedHandle(handle: number | IHandle<WebXRInputSource>): void {
        RemoveHandle(handle, this._inputSourceAddedHandles);
    }

    /**
     * 添加移除输入源时的回调函数对象
     * @param func 回调函数
     * @returns 回调函数对象
     */
    public onRemoved(func: { (data: WebXRInputSource): void }): IHandle<WebXRInputSource> {
        return CreateHandleTo<WebXRInputSource>(func, this._inputSourceRemovedHandles);
    }

    /**
     * 移除输入源被移除时的回调函数对象
     * @param handle 回调函数对象或其id
     */
    public removeRemovedHandle(handle: number | IHandle<WebXRInputSource>): void {
        RemoveHandle(handle, this._inputSourceRemovedHandles);
    }

    /**
     * 添加控制器初始化时的回调函数对象
     * @param func 回调函数
     * @returns 回调函数对象
     */
    public onInit(func: { (data: WebXRAbstractMotionController): void }): IHandle<WebXRAbstractMotionController> {
        return CreateHandleTo<WebXRAbstractMotionController>(func, this._motionControllerInitHandles);
    }

    /**
     * 移除控制器初始化时的回调函数对象
     * @param handle 回调函数对象或其id
     */
    public removeInitHandle(handle: number | IHandle<WebXRAbstractMotionController>): void {
        RemoveHandle(handle, this._motionControllerInitHandles);
    }

    /**
     * 添加控制器模型加载完成时的回调函数对象
     * @param func 回调函数
     * @returns 回调函数对象
     */
    public onLoaded(func: { (data: AbstractMesh): void }): IHandle<AbstractMesh> {
        return CreateHandleTo<AbstractMesh>(func, this._meshLoadedHandles);
    }

    /**
     * 移除控制器模型加载完成时的回调函数对象
     * @param handle 回调函数对象或其id
     */
    public removeLoadedHandle(handle: number | IHandle<AbstractMesh>): void {
        RemoveHandle(handle, this._meshLoadedHandles);
    }

}


export { XRInput };
export type { IXRInputOptions };